import WebGL = Laya.WebGL;

// 程序入口
class GameMain{
    private role:Role
    private modes:string = "exactfit"
    private heroHp:number = 5
    //敌机血量
    private hps:Array<any> = [1,3,5]
    //敌机速度
    private speeds:Array<any> = [3,2,1]
    //敌机被击半径
    private radius:Array<any> = [15,30,70]
    //子弹发射偏移量
    private bulletPos:Array<Array<number>> = [[0],[-15,15],[-30,0,30],[-45,-15,15,45],[-50,-25,0,25,50]]
    //关卡等级
    private level:number = 0
    //积分成绩
    private score:number = 0
    //升级等级所需成绩数量
    private levelUpScore:number = 10
    //子弹级别
    private bulletLevel:number = 0
    //游戏角色容器
    private roleBox:Laya.Sprite 
    //游戏UI界面
    private gameInfo:GameInfo

    constructor()
    {
        Laya.init(400,852, WebGL);
        Laya.loader.load('res/war.atlas',Laya.Handler.create(this,this.onLoadRes))
        Laya.stage.scaleMode = this.modes
       
    }

    /**
     * 资源加载完毕后回调
     */
    onLoadRes(){
        Laya.stage.addChild(new BackGround())
        this.roleBox = new Laya.Sprite()
        this.gameInfo = new GameInfo({hp:this.heroHp})
        Laya.stage.addChild(this.roleBox)
        Laya.stage.addChild(this.gameInfo)
        this.role = new Role()
         this.roleBox.addChild(this.role)
        this.restart()
    }

    /**
     * 游戏帧频主循环
     */
    private onLoop():void{
        for(var i:number = this.roleBox.numChildren-1;i>-1;i--){
            let role:Role = this.roleBox.getChildAt(i) as Role
            this.recycleHandle(role)
            this.createBullet(role)
        }
        this.testCrash()
        this.addEnemy()
        this.gameOver()
    }



    /**
     * 添加敌机
     */
    addEnemy(){
        //关卡越高，创建敌机间隔越短
        var cutTime:number = this.level < 30 ? this.level * 2 : 60;
        //关卡越高，敌机飞行速度越快
        var speedUp:number = Math.floor(this.level / 6);
        //关卡越高，敌机血量越高
        var hpUp:number = Math.floor(this.level / 8);
        //关卡越高，敌机数量越多
        var numUp:number = Math.floor(this.level / 10);

        //生成小飞机
        if(Laya.timer.currFrame % (80 - cutTime ) === 0){
            console.info('小飞机')
            console.info(cutTime)
            this.createEnemy(0,2+numUp,3+speedUp,1);
        }
        //生成中型飞机
        if(Laya.timer.currFrame % (300 - cutTime*4 ) === 0){
            console.info('中飞机')
            this.createEnemy(1,1+numUp,2+speedUp,2+hpUp*2);
        }
        //生成boss
        if(Laya.timer.currFrame % (900 - cutTime * 4) === 0){
            console.info('大飞机')
            this.createEnemy(2,1,1+speedUp,10+hpUp *6);
            //播放boss出场声音
            Laya.SoundManager.playSound("res/sound/enemy3_out.mp3");
        }
    }


    /**
     * 创建敌机
     * @param num 创建数量 
     */
    createEnemy(type:number,num:number,speed:number,hp:number):void{
        for(var i:number = 0;i<num;i++){
            //随机出现敌人
            // var r:number = Math.random();
            // //根据随机数，随机敌人
            // var type:number = r<0.7?0:r<0.95?1:2;
            //创建敌人
            var enemy:Role = Laya.Pool.getItemByClass("role",Role);
            //初始化角色
            enemy.init("enemy"+(type+1),1,hp,speed,this.radius[type]);
            //随机位置
            enemy.pos(Math.random()*400+40,-Math.random()*200 - 100);
            //添加到舞台上
            this.roleBox.addChild(enemy);

        }
    }


    /**
     * 主机死亡检测，结束游戏
     */
    gameOver(){
        if(this.role.hp<1){
            Laya.SoundManager.playSound("res/sound/game_over.mp3");
            Laya.timer.clear(this,this.onLoop)
            //显示提示信息
            this.gameInfo.infoLabel.text = "GameOver,分数："+this.score + "\n点击这里重新开始游戏。";
            //注册舞台点击事件，点击重新开始游戏
            this.gameInfo.infoLabel.once(Laya.Event.CLICK,this,this.restart);
        }
    }


    /**
     * 子弹和敌机回收检测和处理
     * @param role 
     */
    recycleHandle(role:Role):void{
        if(role && role.speed){
            role.y +=role.speed
            if(role.y>1000 || !role.visible || (role.isBullet && role.y < -40)){
                role.visible  = true
                role.isBullet = false
                Laya.Pool.recover('role',role)
                role.removeSelf()
            }
        }
    }

    /**
     * 创建子弹
     * @param role 
     */
    createBullet(role:Role):void{    
        if(role.shootType>0){   
            var time:number = Laya.Browser.now()
            if(time>role.shootTime){        
                this.bulletPos[role.shootType-1].map((v)=>{
                    role.shootTime = time + role.shootInterval
                    let bullet = Laya.Pool.getItemByClass('role',Role)
                    // let bullet:Role = new Role() 
                    bullet.init('bullet1',role.camp,1,-4-role.shootType - Math.floor(this.level / 15),1,1)
                    bullet.pos(role.x+v,role.y - role.hitRadius-10)
                    bullet.isBullet = true
                    this.roleBox.addChild(bullet)

                })
            }
        }
    }

    /**
     * 碰撞检测
     */
    testCrash():void{
        for(var i:number = this.roleBox.numChildren-1;i>-1;i--){
             let role1:Role = this.roleBox.getChildAt(i) as Role
             //判断是否已死亡
             if(role1.hp<1)continue
             for(let j:number=i-1;j>=0;j--){
                //如果角色已死亡，则忽略
                if(!role1.visible)continue
                let role2:Role = this.roleBox.getChildAt(j) as Role

                //如果角色未死亡，并且阵营不同才能进行碰撞
                if(role2.hp>0 && role1.camp != role2.camp){

                    //计算碰撞区域
                    var hitRadius:number = role1.hitRadius + role2.hitRadius;
                    //根据距离判断是否碰撞
        
                    if(Math.abs(role1.x - role2.x) < hitRadius && Math.abs(role1.y - role2.y) < hitRadius){
                        //碰撞之后掉血
                        this.lostHp(role1,1);
                        this.lostHp(role2,1);
                        this.addScore()
                        this.passGame()
                    }
                }
             }
        }
    }

    /**
     * 增加积分
     */
    addScore():void{
        this.score++;
        this.gameInfo.score(this.score)
    }

    /**
     * 游戏过关
     */
    passGame():void{
        if(this.score > this.levelUpScore){
            this.level++
            this.levelUpScore+=this.level * 5;
            this.gameInfo.level(this.level)
        }
    }

    /**
     * 掉血处理
     * @param role 
     * @param hp 掉血数
     */
    lostHp(role:Role,hp:number):void{
        role.hp -= hp
        if(role.type=='hero'){
            this.gameInfo.hp(role.hp)
        }

        if(this.getDropOut(role))return
        if(role.hp>0){
            role.playAction('hit')
             Laya.SoundManager.playSound("res/sound/bullet.mp3");
        }else{
            if(role.isBullet){
                role.visible = false
            }else{
                role.playAction('down')
                this.createDropOut(role)
                Laya.SoundManager.playSound("res/sound/"+role.type+"_down.mp3");
            }
        }
    }

    /**
     * 创建掉落物品
     * @param role 敌机对象 
     */
     createDropOut(role:Role):void{
         //击中boss掉落血瓶或子弹升级道具
        if(role.type == "enemy3"){
            //随机是子弹升级道具还是血瓶
            var type:number = Math.random() < 0.5 ? 2: 3;
            //掉落血瓶或者是子弹升级道具
            var item:Role = Laya.Pool.getItemByClass("role",Role);
            //初始化信息
            item.init("ufo"+(type - 1),role.camp,1,1,15,type);
            //设置位置
            item.pos(role.x,role.y);
            //添加到舞台上
            this.roleBox.addChild(item);
        }
     }

     /**
      * 获取掉落的物品
      */
     getDropOut(role:Role):boolean{
         var a = false
         const fun = {
             /**
              * 获取子弹升级道具
              */
             getDropOut2:()=>{
                //每次吃一个子弹升级道具，子弹升级+1
                this.bulletLevel++;
                //子弹每升2级，子弹数量增加1，最大数量是4
                this.role.shootType = Math.min(Math.floor(this.bulletLevel / 2) + 1,5);
                //子弹级别越高，发射频率越快
                this.role.shootInterval = 500 - 20 * (this.bulletLevel > 20 ? 20 : this.bulletLevel);
                //隐藏道具
                role.visible = false;
                //播放获得道具声音
                Laya.SoundManager.playSound("res/sound/achievement.mp3");
             },

             /**
              * 获取血瓶
              */
             getDropOut3:()=>{
                //每吃一个血瓶，血量增加1
                this.role.hp++;
                //设置最大血量不超过10
                if(this.role.hp > 10) this.role.hp = 10;
                //隐藏道具
                role.visible = false;
                this.gameInfo.hp(this.role.hp)
                //播放获得道具声音
                Laya.SoundManager.playSound("res/sound/achievement.mp3");
             }
         }

         fun['getDropOut'+role.heroType]&&(()=>{fun['getDropOut'+role.heroType]();a = true})()
         return a
     }

    /**
     * 设置主机位置，跟随鼠标
     * @param
     */
    onMouseMove(e):void{
        this.role.pos(Laya.stage.mouseX,Laya.stage.mouseY)
    }

    restart():void{
        //重置游戏数据
        this.score = 0;
        this.level = 0;
        this.levelUpScore = 10;
        this.bulletLevel = 0;
        this.gameInfo.reset();

        //初始化角色
        this.role.init("hero",0,this.heroHp,0,30);
        //设置射击类型
        this.role.shootType = 1;
        //设置角色位置
        this.role.pos(200,500);
        //重置射击间隔
        this.role.shootInterval = 500;
        //显示角色
        this.role.visible = true;
        console.info(this.role)

        for(var i:number = this.roleBox.numChildren-1;i>-1;i--){
            var role:Role = this.roleBox.getChildAt(i) as Role;
            if(role != this.role){
                role.removeSelf();
                //回收之前重置的信息
                role.visible = true;
                //回收到对象池
                Laya.Pool.recover("role",role);
            }
        }
        this.resume();
    }

    /**
     * 暂停游戏
     */
    pause():void{
       //停止游戏主循环
        Laya.timer.clear(this,this.onLoop);
        //移除舞台的鼠标移动事件
        Laya.stage.off(Laya.Event.MOUSE_MOVE,this,this.onMouseMove);
    }

    /**
     * 回复开始游戏
     */
    resume():void{
        Laya.stage.on(Laya.Event.MOUSE_MOVE,this,this.onMouseMove)
        Laya.timer.frameLoop(1,this,this.onLoop)
    }

}
var gameInstance:GameMain =  new GameMain();